package lock

import (
	"fmt"
	"sync"
	"time"
)

func result() {
	var mu sync.RWMutex

	// writer,稍微等待，然后制造一个调用Lock的场景
	go func() {
		time.Sleep(200 * time.Millisecond)
		mu.Lock()
		fmt.Println("Lock")
		time.Sleep(100 * time.Millisecond)
		mu.Unlock()
		fmt.Println("Unlock")
	}()

	go func() {
		factorial(&mu, 10) // 计算10的阶乘, 10!
	}()

	select {}
}

// 递归调用计算阶乘 递归会出现死锁
func factorial(m *sync.RWMutex, n int) int {
	if n < 1 { // 阶乘退出条件
		return 0
	}
	fmt.Println("RLock")
	m.RLock()
	defer func() {
		fmt.Println("RUnlock")
		m.RUnlock()
	}()
	time.Sleep(100 * time.Millisecond)
	return factorial(m, n-1) * n // 递归调用
}

func sum() int {
	var counter Counter
	doneCh := make(chan bool)
	defer close(doneCh)

	for i := 0; i < 3; i++ { // 10个reader
		go func() {
			ticker := time.NewTicker(500 * time.Millisecond)
			for range ticker.C {
				select {
				case done := <-doneCh:
					if done {
						fmt.Println("It's over!", counter.count)
						return
					}
				default:
					count := counter.Count() // 计数器读操作
					fmt.Printf("count %v \n", count)
					time.Sleep(1 * time.Millisecond)
				}
			}
		}()
	}

	for i := 0; i < 10; i++ { // 一个writer
		counter.Incr() // 计数器写操作
		time.Sleep(1 * time.Second)
	}

	doneCh <- true

	return int(counter.count)
}

// 一个线程安全的计数器
type Counter struct {
	mu    sync.RWMutex
	count uint64
}

// 使用写锁保护
func (c *Counter) Incr() {
	c.mu.Lock()
	c.count++
	c.mu.Unlock()
}

// 使用读锁保护
func (c *Counter) Count() uint64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.count
}
